#include "list.h"

ListNode* NewListNode()
{
	ListNode *node = NULL;
	node = (ListNode*)malloc( sizeof(ListNode) );
	if (node == NULL)
		return NULL;
	memset(node, 0x00, sizeof(ListNode));
	node->prev = NULL;
	node->next = NULL;
	node->data = NULL;
	node->datalen = 0;
	return node;
}

void FreeListNode(ListNode *node)
{
	if (node != NULL) {
		free(node);
		node = NULL;
	}
}

void FreeListNodeAndData(ListNode *node, FreeDataFunc freedata) 
{
	if (node != NULL)
	{
		if (node->data != NULL) {
				freedata( node->data );
		}
		free(node);
		node = NULL;
	}
}	

ListHead* NewListHead() 
{
	ListHead *head = NULL;
	head = (ListHead*)malloc( sizeof(ListHead) );
	if (head == NULL)
		return NULL;
	head->first = NULL;
	head->last = NULL;
	head->curr = NULL;
	head->NodeCnt = 0;
	
	return head;
}

void FreeListHead( ListHead *head )
{
	if (head != NULL)
	{
		free(head);
		head = NULL;
	}
}

void* FindDataInList( ListHead *head, void *data, DataCmpFunc func)
{
	if (head == NULL || head->NodeCnt == 0 )
		return NULL;

	head->curr = head->first;	
	while (head->curr) {
		if (func ) {
			//使用func比较
			if( (*func)( head->curr->data,data) == 0 ) 
				break;
		}	
		else {
			//自身比较
			if (data == head->curr->data)
				break;
		}
		head->curr = head->curr->next;
	}
	if (head->curr)
		return head->curr->data;
	return  NULL;
}
ListNode* FindNodeInList( ListHead *head, void *data, DataCmpFunc func)
{
	if (head == NULL || head->NodeCnt == 0 )
		return NULL;

	head->curr = head->first;	
	while (head->curr) {
		if (func ) {
			//使用func比较
			if( (*func)( head->curr->data,data) == 0 ) 
				break;
		}	
		else {
			//自身比较
			if (data == head->curr->data)
				break;
		}
		head->curr = head->curr->next;
	}

	return head->curr;
}

ListNode* RFindNodeInList( ListHead *head, void *data, DataCmpFunc func)
{
	if (head == NULL || head->NodeCnt == 0)
		return NULL;

	head->curr = head->last;	
	while (head->curr) {
		if (func) {
			if ( func( head->curr->data, data) == 0 ) 
				break;
		}	
		else {
			if (data == head->curr->data)
				break;
		}
		head->curr = head->curr->prev;
	}

	return head->curr;
}
void* RFindDataInList( ListHead *head, void *data, DataCmpFunc func)
{
	if (head == NULL || head->NodeCnt == 0)
		return NULL;

	head->curr = head->last;	
	while (head->curr) {
		if (func) {
			if ( func( head->curr->data, data) == 0 ) 
				break;
		}	
		else {
			if (data == head->curr->data)
				break;
		}
		head->curr = head->curr->prev;
	}
	if (head->curr) 
		return head->curr->data;
	return NULL;
}

int InsertNodeBeTheFirst( ListHead *head, ListNode *node)
{
	if (head == NULL || node == NULL)
		return ARGISNULL;
	if (head->NodeCnt == 0) {
		head->first = node;
		head->last = node;
	}
	else {
		head->first->prev = node;
		node->prev = NULL;
		node->next = head->first;
		head->first = node;
	}
	head->NodeCnt++;
	return 0;
}	
int InsertDataBeTheFirst( ListHead *head, void *data )
{
	if (head == NULL || data == NULL)
		return ARGISNULL;
	ListNode *node = NewListNode();
	if (node == NULL)
		return -1;
	node->data = data;
	InsertNodeBeTheFirst( head, node );
}
int InsertNodeBeTheLast( ListHead *head, ListNode *node)
{
	if (head == NULL || node == NULL)
		return ARGISNULL;
	if (head->NodeCnt == 0) {
		head->first = node;
		head->last = node;
	}
	else {
		head->last->next = node;
		node->next = NULL;
		node->prev = head->last;
		head->last = node;
	}
	head->NodeCnt++;
	return 0;
}
int InsertDataBeTheLast( ListHead *head, void *data )
{
	if (head == NULL || data == NULL)
		return ARGISNULL;
	ListNode *node = NewListNode();
	if (node == NULL)
		return -1;
	node->data = data;
	InsertNodeBeTheLast( head, node );
	return 0;
}
int InsertNodeBefore( ListHead *head, ListNode *a, ListNode *InNode )
{
	if (head == NULL || a == NULL || InNode == NULL )
		return ARGISNULL;
	if (head->NodeCnt <= 0)
		return -1;
	if (head->first == a) {
		head->first = InNode;
		InNode->next = a;
		a->prev = InNode;
		InNode->prev = NULL;
	}
	else {
		InNode->next = a;
		InNode->prev = a->prev;
		InNode->prev->next = InNode;
		a->prev = InNode;
	}
	head->NodeCnt++;
	return 0;
}

int InsertNodeAfter( ListHead *head, ListNode *a, ListNode *InNode )
{
	if (head == NULL || a == NULL || InNode == NULL )
		return ARGISNULL;
	if (head->NodeCnt <= 0)
		return -1;
	if (head->last == a) {
		head->last = InNode;
		InNode->prev = a;
		a->next = InNode;
		InNode->next = NULL;
	}
	else {
		InNode->prev = a;
		InNode->next = a->next;
		InNode->next->prev = InNode;
		a->next = InNode;
	}
	head->NodeCnt++;
	return 0;
}

int FindDataAndInsertBefore( ListHead *head, void *data, void *inData, DataCmpFunc func )
{
	int ret  = 0;
	ListNode *node = NULL;
	if (head == NULL || data == NULL )
		return ARGISNULL;

	node = FindDataInList( head, data, func );
	if (node == NULL )
		return NOTFOUND;
	ListNode *newNode = NewListNode();
	newNode->data = inData;
	ret = InsertNodeBefore( head, node, newNode );
	if (ret) {
		FreeListNode(newNode);
		return -1;
	}
	return 0;	
}
int FindDataAndInsertAfter( ListHead *head, void *data, void *inData, DataCmpFunc func )
{
	int ret  = 0;
	ListNode *node = NULL;
	if (head == NULL || data == NULL )
		return ARGISNULL;

	node = FindDataInList( head, data, func );
	if (node == NULL )
		return NOTFOUND;
	ListNode *newNode = NewListNode();
	newNode->data = inData;
	ret = InsertNodeAfter( head, node, newNode );
	if (ret) {
		FreeListNode(newNode);
		return -1;
	}
	return 0;	
}
int __DeleteListNode( ListHead *head, ListNode *node )
{
	if (head == NULL || node == NULL )
		return 0;
	else if (head == NULL && node != NULL )
		return -1;
	else if (head->NodeCnt == 0 && node != NULL )
		return -1;

	if (head->NodeCnt <= 0)
		return 0;
	if (head->NodeCnt == 1) {
		head->first = NULL;
		head->last = NULL;
	}
	else if (node->prev == NULL) {
		head->first = node->next;
		node->next->prev = NULL;
	}
	else if(node->next == NULL) {
		head->last = node->prev;
		node->prev->next = NULL;
	}
	else {
		node->next->prev = node->prev;
		node->prev->next = node->next;
	}
	head->NodeCnt--;
	return 0;
}
int DeleteListNodeAndData( ListHead *head, ListNode *node, FreeDataFunc freeFunc )
{
	if (freeFunc == NULL)
		return -2;
	int ret  = __DeleteListNode(head, node);
	freeFunc(node->data);
	FreeListNode(node);
	return 0;
}
int DeleteListNode( ListHead *head, ListNode* node)
{
	int ret = 0;
	ret = __DeleteListNode(head, node);
	FreeListNode(node);
	return ret;
}

int FindAndDeleteNodeAndDataAll( ListHead *head, void *data, DataCmpFunc cmp, FreeDataFunc freeFunc)
{
	int ret = 0;
	ListNode *node = NULL;
	int cnt = 0;

	if (head == NULL || data == NULL || cmp == NULL )
		return 0;

	head->curr = head->first;
	while (head->curr)
	{
		if ( (*cmp)(head->curr->data, data) == 0 ) {
			ret = DeleteListNodeAndData(head, node, freeFunc);
			if (ret)
				return -cnt;
			cnt++;
		}
		head->curr = head->curr->next;
	}	
	return cnt;
}
int FindAndDeleteNodeAll( ListHead *head, void *data, DataCmpFunc cmp )
{
	int ret = 0;
	ListNode *node = NULL;
	int cnt = 0;

	if (head == NULL || data == NULL || cmp == NULL )
		return 0;
	cnt = FindAndDeleteNodeAndDataAll( head, data, cmp, NULL);
	return cnt;
}
int FindAndDeleteNodeAndData( ListHead *head, void *data, DataCmpFunc cmp , FreeDataFunc freeFunc)
{
	int ret = 0;
	ListNode *node = NULL;
	if (freeFunc == NULL )
		return -2;
	if (head == NULL || data == NULL || cmp == NULL )
		return 0;

	node = FindDataInList( head, data, cmp );
	if (node != NULL) {
		ret = DeleteListNodeAndData(head, node, freeFunc);
		if (ret)
			return -1;
		return 1;
	}
	else 
		return 0;

}
int FindDataAndDeleteNode( ListHead *head, void *data, DataCmpFunc cmp)
{
	int ret = 0;
	ListNode *node = NULL;

	if (head == NULL || data == NULL || cmp == NULL )
		return 0;
	node = FindDataInList( head, data, cmp );
	if (node != NULL) {
		ret = DeleteListNode(head, node);
		if (ret)
			return -1; 
		return 1;
	}  
	return ret;
}
int DamageList( ListHead *head, FreeDataFunc freeFunc )
{
	int		r = 0;
	if (head == NULL)
		return;

	while (head->NodeCnt && head->first) {
		head->curr = head->first;
		head->first = head->first->next;
		r = DeleteListNodeAndData( head, head->curr, freeFunc );
		if (r)
			return -1;
	}
	FreeListHead( head );
	return 0;
}
int DamageListNode(ListHead *head, FreeDataFunc freeFunc)
{
	int		r = 0;
	if (head == NULL)
		return;

	while (head->NodeCnt && head->first) {
		head->curr = head->first;
		head->first = head->first->next;
		r = DeleteListNodeAndData( head, head->curr, freeFunc );
		if (r)
			return -1;
	}
	head->first = NULL;
	head->last = NULL;
	head->curr = NULL;
	head->NodeCnt = 0;
	return 0;
}
int TraversalList( ListHead *head, TraversalFunc func)
{
	int r = 0;
	if (head == NULL || func == NULL)
		return;
	head->curr = head->first;
	while (head->curr) {
		r = func(head->curr->data);
		if (r) {
			return r;
		}
		head->curr = head->curr->next;
	}	
	return 0;
}	
int TraversalListWithData( ListHead *head, TraversalFuncWithData func, void *data)
{
	int r;
	if (head == NULL || func == NULL)
		return;
	head->curr = head->first;
	while (head->curr) {
		r = func(head->curr->data, data);
		if (r) {
			return r;
		}
		head->curr = head->curr->next;
	}	
	return 0;
}
